﻿using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace AutoCadConvert
{
    public class Lines: Collection
    {
        public List<Line> m_Lines = new List<Line>();
        public Lines(House house) : base(house){}

        public override void AddData(Entity value)
        {
            //添加点数据
            base.AddData(value);
            List<Point> ptLst = m_house.Item<Points>().m_Points;
            m_house.Item<Points>().AddData(value);
            if (value is Autodesk.AutoCAD.DatabaseServices.Line)
            {
                Autodesk.AutoCAD.DatabaseServices.Line entity = value as Autodesk.AutoCAD.DatabaseServices.Line;
                Line line = new Line(entity.Layer == LayerName.instance()[0] ? false : true);
                line.V0 = ptLst.Find(new Predicate<Point>(o => o == new Point(entity.StartPoint)));
                line.V1 = ptLst.Find(new Predicate<Point>(o => o == new Point(entity.EndPoint)));
                m_Lines.Add(line);
            }
            else if (value is Autodesk.AutoCAD.DatabaseServices.Polyline)
            {
                Autodesk.AutoCAD.DatabaseServices.Polyline entity = value as Autodesk.AutoCAD.DatabaseServices.Polyline;
                for (int i = 0; i < entity.NumberOfVertices; i++)
                {
                    if (SegmentType.Line == entity.GetSegmentType(i))
                    {
                        Line line = new Line(entity.Layer == LayerName.instance()[0] ? false : true);
                        line.V0 = ptLst.Find(new Predicate<Point>(o => o == new Point(entity.GetLineSegmentAt(i).StartPoint)));
                        line.V1 = ptLst.Find(new Predicate<Point>(o => o == new Point(entity.GetLineSegmentAt(i).EndPoint)));
                        m_Lines.Add(line);
                    }
                }
            }
        }
        public override void AjustLineAndPoint()
        {
            RecursionCrossLine(m_Lines,m_house.Item<Points>().m_Points);
            IEnumerable<Point> ptSingle = m_house.Item<Points>().m_Points.Where(o => o.refCount == 1);
            if(ptSingle.Count()> 0)
                DwgConvert.PutMessage("请检查墙是否闭合,有{0}个点未闭合", m_house.Item<Points>().m_Points.Where(o => o.refCount == 1).Count());
        }
        public static void RecursionCrossLine(List<Line> lnst,List<Point> ptlst)
        {
            //检查交点
            List<Line> usedLine = new List<Line>();
            Dictionary<Line, List<Line>> tmpCrossLine = new Dictionary<Line, List<Line>>();
            //Dictionary<int, List<int>> tmpCrossLineIdx = new Dictionary<int, List<int>>();
            foreach (Line line in lnst)
            {
                List<Line> linRet = lnst.Where(o => !usedLine.Contains(o)).Where(o => o != line && o.isColide(line)).ToList();
                if (linRet.Count() > 0)
                {
                    tmpCrossLine.Add(line, linRet);
                    //tmpCrossLineIdx.Add(lnst.IndexOf(line), linRet.Select(o => lnst.IndexOf(o)).ToList());
                }
                usedLine.Add(line);
            }
            //添加交点
            foreach (KeyValuePair<Line, List<Line>> keyValue in tmpCrossLine)
            {
                foreach (Line line in keyValue.Value)
                {
                    //确定哪一条线段
                    Point pt = keyValue.Key.getPoint(line);
                    if (double.IsInfinity(pt.X) || double.IsInfinity(pt.Y)
                        || double.IsNaN(pt.X) || double.IsNaN(pt.Y))
                        continue;//去掉重叠
                    //距离最小的点
                    List<double> xPtArray = new List<double>() { (line.V0 - pt).Distance, (line.V1 - pt).Distance, (keyValue.Key.V0 - pt).Distance, (keyValue.Key.V1 - pt).Distance };
                    double dMin = xPtArray.Min();
                    if (dMin <= 0.5 && xPtArray.IndexOf(dMin) < 2 && lnst.Contains(keyValue.Key))
                    {
                        pt = xPtArray.IndexOf(dMin) == 0 ? line.V0 : line.V1;//交点
                        lnst.AddRange(new Line[] {
                            new Line(keyValue.Key.V0,pt),
                            new Line(pt,keyValue.Key.V1),
                        });
                        pt.refCount += 2;
                        lnst.Remove(keyValue.Key);
                    }
                    else if (dMin <= 0.5 && xPtArray.IndexOf(dMin) >= 2 && lnst.Contains(line))
                    {
                        pt = xPtArray.IndexOf(dMin) == 2 ? keyValue.Key.V0 : keyValue.Key.V1;//交点
                        lnst.AddRange(new Line[] {
                            new Line(line.V0,pt),
                            new Line(pt,line.V1),
                        });
                        pt.refCount += 2;
                        lnst.Remove(line);
                    }
                    else if (lnst.Contains(keyValue.Key) && lnst.Contains(line))
                    {//相交无端点在交点上
                        pt.index = ptlst.Count;
                        ptlst.Add(pt);
                        lnst.AddRange(new Line[] {
                            new Line(line.V0,pt),
                            new Line(pt,line.V1),
                            new Line(keyValue.Key.V0,pt),
                            new Line(pt,keyValue.Key.V1),
                        });
                        pt.refCount += 3;
                        lnst.Remove(keyValue.Key);
                        lnst.Remove(line);
                    }
                }
            }
            if (tmpCrossLine.Count > 0)
            {
                RecursionCrossLine(lnst, ptlst);//重复检测交叉线
            }
        }
        public override IEnumerable<XElement> ToXml()
        {
            int idx = 0;
            foreach (Line line in m_Lines)
                yield return new XElement("_" + idx++, line.ToXml());
        }
        public override IEnumerable<BspObject> FromXml(XElement node)
        {
            int idx = 0;
            foreach (XElement it in node.Elements())
            {
                Line line = new Line();
                line.FromXml(it);
                yield return line;
            }
        }
    }
}
